﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
//using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;
using System.Xml.Linq;

namespace DBMLMassager
{
	/// <summary>
	/// Interaction logic for Window1.xaml
	/// </summary>
	public partial class Window1 : Window
	{
		public Window1()
		{
			InitializeComponent();
			if (!string.IsNullOrEmpty(Properties.Settings.Default.LastFilePath))
			{
				FileTB.Text = Properties.Settings.Default.LastFilePath;
				setOperationButtonEnabledStatuses();
			}
		}



		private void showBrowseDialog()
		{
			OpenFileDialog ofd = new OpenFileDialog();
			ofd.Filter = ".dbml Files|*.dbml";

			string lastDir = "c:\\";
			if (!string.IsNullOrEmpty(Properties.Settings.Default.LastFilePath))
			{
				string desiredLastDir = System.IO.Path.GetDirectoryName(Properties.Settings.Default.LastFilePath);
				if (Directory.Exists(desiredLastDir))
				{
					lastDir = desiredLastDir;
				}
			}

			ofd.InitialDirectory = lastDir;

			if (ofd.ShowDialog() == true)
			{
				FileTB.Text = ofd.FileName;
				Properties.Settings.Default.LastFilePath = ofd.FileName;
				Properties.Settings.Default.Save();
			}

			setOperationButtonEnabledStatuses();
		}

		private void setOperationButtonEnabledStatuses()
		{
			MassageBTN.IsEnabled = GenerateDTBTN.IsEnabled = GenerateMTBTN.IsEnabled = !(string.IsNullOrEmpty(FileTB.Text));
		}

		private void BrowseBTN_Click(object sender, RoutedEventArgs e)
		{
			showBrowseDialog();
		}

		private void MassageBTN_Click(object sender, RoutedEventArgs e)
		{
			massageFile();
		}

		private void massageFile()
		{
			OutputTB.Text = string.Empty;
			logMessage("Beginning Massage . . .");
			XElement xe = loadDBML();
			XNamespace ns = getNamespace();
			var tables = getTables(xe, ns);
			logMessage("{0} tables found.", tables.Count());
			foreach (XElement table in tables)
			{
				var cols = getColumns(ns, table);
				string name = getNameAttributeVal(table);
				logMessage("Table: {0} has {1} columns.", name, cols.Count());

				foreach (XElement col in cols)
				{
					name = getNameAttributeVal(col);
					logMessage("Processing column {0}", name);
					col.SetAttributeValue("UpdateCheck", "Never");
				}
			}

			backupOldSaveNew(xe);
			logMessage("Massage finished.");
			logMessage("Finished.");
		}

		private void backupOldSaveNew(XElement xe)
		{
			logMessage("Saving file . . . (backup will be in same diretctory with '.bak' extension)");
			string backupPath = Path.Combine(Path.GetDirectoryName(FileTB.Text), string.Concat(Path.GetFileNameWithoutExtension(FileTB.Text), ".bak"));
			if (File.Exists(backupPath))
			{
				File.Delete(backupPath);
			}
			File.Copy(FileTB.Text, backupPath);
			xe.Save(FileTB.Text);
		}

		private void fixCasing()
		{
			OutputTB.Text = string.Empty;
			logMessage("Beginning fix casing . . .");
			XElement xe = loadDBML();

			XNamespace ns = getNamespace();

			var tables = getTables(xe, ns);
			logMessage("{0} tables found.", tables.Count());
			foreach (XElement table in tables)
			{
				//fix member casing
				string member = table.Attribute("Member").Value;
				if (firstIsLower(member))
				{
					string uMember = uppercaseFirst(member);
					logMessage("Setting Member attribute to {0}", uMember);
					table.SetAttributeValue("Member", uMember);
				}
				//fix type casing
				XElement type = table.Element(ns + "Type");
				string typeName = getNameAttributeVal(type);
				if (firstIsLower(typeName))
				{
					string uType = uppercaseFirst(typeName);
					logMessage("Setting Type attribute to {0}", uType);
					type.SetAttributeValue("Name", uType);
				}
				//fix colname casing
				var cols = getColumns(ns, table);

				string name = getNameAttributeVal(table);
				logMessage("Table: {0} has {1} columns.", name, cols.Count());

				foreach (XElement col in cols)
				{
					name = getNameAttributeVal(col);
					string uName = uppercaseFirst(name);
					logMessage("Field {0} will be {1}.", name, uName);
					col.SetAttributeValue("Name", uName);
				}
			}
			backupOldSaveNew(xe);
			logMessage("Fix casing complete.");
		}

		private bool firstIsLower(string str)
		{
			return char.IsLower(str[0]);
		}

		private string uppercaseFirst(string name)
		{
			string retVal = name[0].ToString().ToUpper();

			retVal = string.Concat(retVal, name.Substring(1, name.Length - 1));

			return retVal;
		}

		private static IEnumerable<XElement> getColumns(XNamespace ns, XElement tableElement)
		{
			var cols = tableElement.Elements(ns + "Type").Elements(ns + "Column");
			return cols;
		}

		private static string getNameAttributeVal(XElement xe)
		{
			return xe.Attribute("Name").Value;
		}

		private static IEnumerable<XElement> getTables(XElement xe, XNamespace ns)
		{
			var tables = xe.Elements(ns + "Table");
			return tables;
		}

		private static XNamespace getNamespace()
		{
			XNamespace ns = "http://schemas.microsoft.com/linqtosql/dbml/2007";
			return ns;
		}

		private XElement loadDBML()
		{
			XElement xe = XElement.Load(string.Concat("file://", FileTB.Text));
			return xe;
		}

		private void logMessage(string msg, params object[] parms)
		{
			OutputTB.Text = string.Concat(OutputTB.Text, string.Format(msg, parms), "\r\n");
			OutputSV.ScrollToEnd();
		}

		private void GenerateDTBTN_Click(object sender, RoutedEventArgs e)
		{
			generateDataTier();
		}

		private void generateDataTier()
		{
			OutputTB.Text = string.Empty;

			logMessage("Beginning generation of DataTier files.");
			XElement xe = loadDBML();
			XNamespace ns = getNamespace();
			var tables = getTables(xe, ns);
			string template = getTemplateAsString("PartialDBClass.cs");

			YesNoToAllDialog.Results? yesNoResult = null;

			foreach (XElement table in tables)
			{
				string thisTemplate = template;
				string name = getTypeName(ns, table);
				logMessage("Generating '{0}' DataTier class.", name);
				//string primaryKey = getPrimaryKey(ns, table);
				thisTemplate = thisTemplate.Replace("%%ClassName%%", name);
				//thisTemplate = thisTemplate.Replace("%%PrimaryKey%%", primaryKey);
				yesNoResult = saveDataTierTemplate(string.Concat(name, ".cs"), thisTemplate, yesNoResult);
				if (yesNoResult == YesNoToAllDialog.Results.Cancel)
				{
					logMessage("Generation of data tier files cancelled by user.");
					break;
				}
			}

			logMessage("Done generating DataTier files.");
		}

		private YesNoToAllDialog.Results? saveDataTierTemplate(string filename, string templateContents, YesNoToAllDialog.Results? yesNoToAllResult)
		{
			string saveDir = Path.GetDirectoryName(FileTB.Text);
			return saveTemplate(filename, templateContents, saveDir, yesNoToAllResult);
		}



		private YesNoToAllDialog.Results? saveTemplate(string filename, string templateContents, string saveDir, YesNoToAllDialog.Results? yesNoToAllResult)
		{
			string savePath = Path.Combine(saveDir, filename);
			bool fileExists = File.Exists(savePath);
			if (fileExists && yesNoToAllResult == null)
			{
				//if (MessageBox.Show(this, string.Format("File {0} already exists.  Overwrite?", filename), "File Already Exists", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
				YesNoToAllDialog dia = new YesNoToAllDialog();
				dia.Owner = this;
				dia.Title = "File Already Exists";
				dia.DialogText = string.Format("File {0} already exists.  Overwrite?", filename);
				if (dia.ShowDialog() == true)
				{
					yesNoToAllResult = dia.Result;
				}
			}

			if (fileExists)
			{
				if (yesNoToAllResult == YesNoToAllDialog.Results.Yes || yesNoToAllResult == YesNoToAllDialog.Results.YesToAll)
				{
					File.Delete(savePath);
				}
				else 
				{
					return yesNoToAllResult;
				}
			}
			
			using (TextWriter tw = new StreamWriter(savePath))
			{
				tw.Write(templateContents);
			}

			return yesNoToAllResult;
		}

		private string getTypeName(XNamespace ns, XElement table)
		{
			return getNameAttributeVal(table.Element(ns + "Type"));
		}

		private string getPrimaryKey(XNamespace ns, XElement table)
		{
			XElement primCol = null;
			try
			{
				primCol = (from el in table.Elements(ns + "Type").Elements(ns + "Column")
						   where (bool)el.Attribute("IsPrimaryKey") == true
						   select el).FirstOrDefault();
			}
			catch { }

			if (primCol == null)
			{
				return "UNAVAILABLE";
			}

			string retVal;

			if (primCol.Attribute("Memeber") != null)
			{
				retVal = primCol.Attribute("Member").Value;
			}
			else
			{
				retVal = primCol.Attribute("Name").Value;
			}
			return retVal;
		}


		private string getTemplateAsString(string templateClassName)
		{
			string templatesPath = getTemplatesPath();
			string filename = string.Concat(templateClassName, ".template");
			string templatePath = Path.Combine(templatesPath, filename);
			using (TextReader tr = File.OpenText(templatePath))
			{
				return tr.ReadToEnd();
			}
		}

		private static string getTemplatesPath()
		{
			string templatesPath = Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Templates");
			return templatesPath;
		}

		private void FixCasingBTN_Click(object sender, RoutedEventArgs e)
		{
			fixCasing();
		}

		private void GenerateMTBTN_Click(object sender, RoutedEventArgs e)
		{
			generateMiddleTier();
		}

		private void generateMiddleTier()
		{
			OutputTB.Text = string.Empty;

			logMessage("Beginning generation of Middle Tier files.");

			string saveFolder = getSaveFolderFromUser();
			if (saveFolder == null)
			{
				MessageBox.Show("You must select a folder to save generated Middle Tier files.");
				logMessage("Generation of Middle Tier files aborted.");
				return;
			}
			XElement xe = loadDBML();
			XNamespace ns = getNamespace();
			var tables = getTables(xe, ns);
			string template = getTemplateAsString("MTClass.cs");

			YesNoToAllDialog.Results? yesNoResult = null;
			foreach (XElement table in tables)
			{
				string thisTemplate = template;
				string name = getTypeName(ns, table);
				logMessage("Generating '{0}' MiddleTier class.", name);
				//string primaryKey = getPrimaryKey(ns, table);
				thisTemplate = thisTemplate.Replace("%%ClassName%%", name);
				//thisTemplate = thisTemplate.Replace("%%PrimaryKey%%", primaryKey);
				yesNoResult = saveTemplate(string.Concat(name, "Extender", ".cs"), thisTemplate, saveFolder, yesNoResult);
				if (yesNoResult == YesNoToAllDialog.Results.Cancel)
				{
					logMessage("Generation of MiddleTier files cancelled by user.");
					break;
				}
			}

			logMessage("Done generating MiddleTier files.");
		}


		private string getSaveFolderFromUser()
		{
			OpenFileDialog ofd = new OpenFileDialog();
			string lastDir = "c:\\";
			if (!string.IsNullOrEmpty(Properties.Settings.Default.LastMiddleTierPath))
			{
				string desiredLastDir = System.IO.Path.GetDirectoryName(Properties.Settings.Default.LastMiddleTierPath);
				if (Directory.Exists(desiredLastDir))
				{
					lastDir = desiredLastDir;
				}
			}

			ofd.InitialDirectory = lastDir;

			ofd.Title = "Please choose a directory to save middle tier files";
			ofd.CheckFileExists = false;
			ofd.FileName = "[Get Folder ...]";
			ofd.Filter = "Folder|no.files";

			if (ofd.ShowDialog() == true)
			{
				Properties.Settings.Default.LastMiddleTierPath = ofd.FileName;
				Properties.Settings.Default.Save();
				string path = Path.GetDirectoryName(ofd.FileName);
				return path;
			}
			else
			{
				return null;
			}
		}


		
	}
}
